package com.dongrj.framework.core.model;

import com.dongrj.framework.core.utils.CollectionUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;


@Setter
@Getter
@ToString(callSuper = true)
public class Page<Model> extends AbstractPage {

    private long total;

    private List<Model> data = new ArrayList<>();

    public Page() {
        super(10, 1);
        this.total = 0;
    }

    public Page(int pageSize, int currentPage) {
        super(pageSize, currentPage);
        this.total = 0;
    }

    public Page(int pageSize, int currentPage, List<Model> data) {
        this(pageSize, currentPage);
        this.data = data;
        this.total = CollectionUtils.size(data);
    }

    public Page(int pageSize, int currentPage, List<Model> data, long total) {
        this(pageSize, currentPage);
        this.data = data;
        this.total = total;
    }

    public <Resp> Page<Resp> map(Function<Model, Resp> function) {
        return map(function, null);
    }

    public <Resp> Page<Resp> map(Function<Model, Resp> function, Consumer<Resp> consumer) {
        return map(this, function, consumer);
    }

    public void forEach(Consumer<Model> consumer) {
        List<Model> data = getData();
        if (CollectionUtils.isNotEmpty(data)) {
            data.forEach(consumer);
        }
    }

    public static <Param extends AbstractPage, M> Page<M> page(Param param, Function<Param, Long> countFunction, Function<Param, List<M>> listFunction) {
        Long count = countFunction.apply(param);
        if (count == 0L) {
            return empty(param);
        }
        List<M> result = listFunction.apply(param);
        return new Page<>(param.getPageSize(), param.getCurrentPage(), result, count);
    }

    public static <Model> Page<Model> empty(AbstractPage param) {
        Page<Model> page = new Page<>(param.getPageSize(), param.getCurrentPage());
        page.setData(new ArrayList<>(0));
        page.setTotal(0L);
        return page;
    }

    public static <Model, Resp> Page<Resp> map(Page<Model> page, Function<Model, Resp> function, Consumer<Resp> consumer) {
        List<Resp> respList = toResp(page.getData(), function, consumer);
        return new Page<>(page.getPageSize(), page.getCurrentPage(), respList, page.getTotal());
    }

    public static <Model, Resp> List<Resp> toResp(List<Model> items, Function<Model, Resp> function, Consumer<Resp> consumer) {
        if (CollectionUtils.isEmpty(items)) {
            return new ArrayList<>(0);
        }
        List<Resp> result = new ArrayList<>(items.size());
        if (consumer == null) {
            for (Model item : items) {
                Resp apply = function.apply(item);
                result.add(apply);
            }
        } else {
            for (Model item : items) {
                Resp apply = function.apply(item);
                consumer.accept(apply);
                result.add(apply);
            }
        }
        return result;
    }
}